package com.atguigu.gulimall.product;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;


/*
* 1.整合mybatis - plus
*   1) 导入依赖
*   2）配置
*     1.配置数据源
*     2.配置mybatis-plus
* 2.逻辑删除
*   1） 配置全局的逻辑删除规则(省略)
*   2） 配置逻辑删除的组件Bean(省略)
*   3) 给bean加上逻辑删除注解 @Toblclogic
*
* 3、JSR303
 *   1）、给Bean添加校验注解:javax.validation.constraints，并定义自己的message提示
 *   2)、开启校验功能@Valid
 *      效果：校验错误以后会有默认的响应；
 *   3）、给校验的bean后紧跟一个BindingResult，就可以获取到校验的结果
 *   4）、分组校验（多场景的复杂校验）
 *         1)、	@NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class})
 *          给校验注解标注什么情况需要进行校验
 *         2）、@Validated({AddGroup.class})
 *         3)、默认没有指定分组的校验注解@NotBlank，在分组校验情况@Validated({AddGroup.class})下不生效，只会在@Validated生效；
 *
 *   5）、自定义校验
 *      1）、编写一个自定义的校验注解
 *      2）、编写一个自定义的校验器 ConstraintValidator
 *      3）、关联自定义的校验器和自定义的校验注解
 *      @Documented
 * @Constraint(validatedBy = { ListValueConstraintValidator.class【可以指定多个不同的校验器，适配不同类型的校验】 })
 * @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
 * @Retention(RUNTIME)
 * public @interface ListValue {
 *
 * 4、统一的异常处理
 * @ControllerAdvice
 *  1）、编写异常处理类，使用@ControllerAdvice。
 *  2）、使用@ExceptionHandler标注方法可以处理的异常。
 *
 * 5.模板引擎
 *  1) 引入依赖
 *  <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    thymeleaf:
        cache: false 关闭缓存
  * 2） 静态资源都放在 static 文件夹下
  * 3）就可以安装路径直接访问
  *
  * 6.页面修改不重启服务器
  * 1） 引入dev tools
  * 2） 修改完页面ctrl shift f9
  * 3) 修改配置还是重启服务器
  *
  * 7.整合redis
  * 1)引入 data-redis-starter
  * 2)简单配置 host 信息
  * 3）使用springboot 自动配置的 StringRedisTemplate 来操作redis
  *
  * 8.整合 redisson 作为分布式锁等功能框架
  * 1）引入依赖 redisson
  * 2）配置
  *
  * 9.整合 springCache 简化缓存开发  用redis 作为缓存
  * 1）引入依赖 spring-boot-starter-cache  spring-boot-starter-data-redis
  * 2）写配置
  *     1.自动配置了哪些
  *         CacheAutoConfiguration 会自动导入 RedisCacheConfigUration 自动配置了缓存管理器 RedisCacheManager
  *     2.我们需要配置哪些
  *     配置使用redis作为缓存
  *     3. 测试使用缓存
  *  @Cacheable: Triggers cache population. 触发将数据保存到缓存的操作
  *  @CacheEvict: Triggers cache eviction.  触发将数据从缓存删除的操作
  *  @CachePut: Updates the cache without interfering with the method execution. 不影响方法执行 更新缓存  双写模式
  *  @Caching: Regroups multiple cache operations to be applied on a method. 组合多个操作
  *  @CacheConfig: Shares some common cache-related settings at class-level. 在类级别共享缓存的相同配置
  *     1.开启缓存功能 @EnableCaching
  *     2.只需要使用注解就能完成缓存操作
  *     3.key 自动生成  缓存的名字（product）::SimpleKey []
  *     4.缓存的value 的值 默认使用jdk序列化机制，将序列化之后的数据 存到redis
  *     5.默认过期时间 -1 永不过期
  *     自定义操作
  *         1.指定生成的缓存使用的key
  *         2.指定缓存的数据存活时间
  *         3.将数据保存为json 格式
  * springCache 的不足？
  * 1. 读模式
  *     1）缓存穿透 ：查询一个null数据。 解决： 缓存空数据  spring.cache.redis.cache-null-values=true
  *     2）缓存雪崩 ：大量的key 同时过期。解决：加上过期时间 spring.cache.redis.time-to-live=3600000
  *     3）缓存击穿 ：大量并发进来同时查询一个正好过期的数据. 解决：加锁  springCache： ？ 默认没有加锁 ,sync = true 解决击穿问题
  * 2.写模式（缓存与数据库数据一致性问题？）
  *     1）读写加锁
  *     2）引入 Canal 中间件  感知到mysql更新去更新数据库
  *     3）读多写多的直接就去查询数据库
  * 总结：
  *      常规数据（读多写少，即时性，一致性要求不高的数据，完全可以使用Spring-Cache）：写模式(只要缓存的数据有过期时间就足够了)
  *      特殊数据：特殊设计
  *  原理：
  *      CacheManager(RedisCacheManager)->Cache(RedisCache)->Cache负责缓存的读写
 */

@EnableRedisHttpSession     //整合Redis作为session存储
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.atguigu.gulimall.product.feign")
public class ProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }
}
